using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Collections;

namespace CommonLibrary
{
    public class JsonFormatterException : Exception
    {
        public int Position { get; set; }
        public string Json { get; set; }

        public JsonFormatterException(string error, int position, string json)
            : base(error)
        {
            this.Position = position;
            this.Json = json;
        }
	}

    internal class JsonReader
    {
		internal enum Symbols
        {
            None = 0,

            /// <summary>
            /// {
            /// </summary>
            BraceLeft,

            /// <summary>
            /// }
            /// </summary>
            BraceRight,

            /// <summary>
            /// [
            /// </summary>
            SquareLeft,  // [

            /// <summary>
            /// ]
            /// </summary>
            SquareRight,  // ]

            /// <summary>
            /// :
            /// </summary>
            Colon,  // :

            /// <summary>
            /// "
            /// </summary>
            DoubleQuot,  // "

            /// <summary>
            /// ,
            /// </summary>
            Comma,  // ,

            String,
            Number,
            True,
            False,
            Null
        }

		internal enum JsonDataType
		{
			Null,
			Object,
			Arrary,
			String,
			Number,
			Boolean,
		}

        private char[] _Buffer;
        private int _Index;

		public JsonDataType DataType{ get; private set; }

        public JsonReader(string json)
        {
            this._Buffer = json.Trim().ToCharArray();
            this._Index = 0;
        }

        public object Parse()
		{
			if (this._Buffer.Length == 0)
				return null;

			switch (GetToken ()) {
			case Symbols.BraceLeft:
				DataType = JsonDataType.Object;
				return ParseObject ();

			case Symbols.SquareLeft:
				DataType = JsonDataType.Arrary;
				return ParseArray ();

			case Symbols.DoubleQuot:
				DataType = JsonDataType.String;
				return ParseString ();

			case Symbols.Number:
				DataType = JsonDataType.Number;
				return ParseNumber ();

			case Symbols.Null:
				DataType = JsonDataType.Null;
				return null;

			case Symbols.True:
				DataType = JsonDataType.Boolean;
				return true;

			case Symbols.False:
				DataType = JsonDataType.Boolean;
				return false;

			default:
				throw new JsonFormatterException ("JSON字符串格式不正确", _Index, new string (_Buffer));
			}
		}

        private object ParseValue()
		{
			switch (GetToken ()) {
			case Symbols.BraceLeft:
				return ParseObject ();

			case Symbols.SquareLeft:
				return ParseArray ();

			case Symbols.DoubleQuot:
				return ParseString ();

			case Symbols.Number:
				return ParseNumber ();

			case Symbols.Null:
				return null;

			case Symbols.True:
				return true;

			case Symbols.False:
				return false;

			default:
				throw new JsonFormatterException ("JSON字符串格式不正确", _Index, new string (_Buffer)); 
			}
		}

        private Hashtable ParseObject()
		{
			Hashtable result = new Hashtable ();

			string key = null;
			while (true) {
				SkipWhiteSpace ();
				CheckEndOfBuffer ();
				if (_Buffer [_Index] == '"') {
					_Index++;
					key = ParseString ();
				} else if (_Buffer [_Index] == '}') {
					_Index++;
					return result;
				} else {
					throw new JsonFormatterException ("无法读取Object类型数据", this._Index, new string (this._Buffer));
				}

				SkipWhiteSpace ();
				CheckEndOfBuffer ();

				if (_Buffer [_Index] != ':')
					throw new JsonFormatterException ("无法读取Object类型数据", this._Index, new string (this._Buffer));
				++_Index;
				result [key] = ParseValue ();

				SkipWhiteSpace ();
				CheckEndOfBuffer ();

				if (_Buffer [_Index] != ',') {
					if (_Buffer [_Index] == '}') {
						++_Index;
						return result;
					}

					throw new JsonFormatterException ("无法读取Object类型数据", this._Index, new string (this._Buffer));
				}

				++_Index;
			}
		}

        private object[] ParseArray()
		{
			ArrayList result = new ArrayList (20);
			SkipWhiteSpace ();
			CheckEndOfBuffer ();

			if (_Buffer [_Index] == ']') {
				++_Index;
				return new object[0];
			}

			while (true) {
				result.Add (ParseValue ());

				SkipWhiteSpace ();
				CheckEndOfBuffer ();
				if (_Buffer [_Index] == ',') {
					++_Index;
					continue;
				} else if (_Buffer [_Index] == ']') {
					++_Index;
					break;
				} else {
					throw new JsonFormatterException ("无法读取Array类型数据", _Index, new string (_Buffer)); 
				}
			}

			return result.ToArray ();
		}

        private string ParseString()
        {
            char ch;
            StringBuilder builder = new StringBuilder(20);
            while (this._Index < this._Buffer.Length)
            {
                ch = _Buffer[_Index];
                ++_Index;

                if (ch == '"')
                {
                    break;
                }
                else if (ch == '\\')
                {
                    // \" \\ \/ \b \f \n \r \t \u
                    if (_Index < this._Buffer.Length)
                    {
                        switch (_Buffer[_Index])
                        {
                            case '"':
                                builder.Append('"');
                                break;

                            case '\\':
                                builder.Append('\\');
                                break;

                            case '/':
                                builder.Append('/');
                                break;

                            case 'b':
                                builder.Append('b');
                                break;

                            case 'f':
                                builder.Append('f');
                                break;

                            case 'n':
                                builder.Append('n');
                                break;

                            case 'r':
                                builder.Append('r');
                                break;

                            case 't':
                                builder.Append('t');
                                break;

                            case 'u':
                                uint h1, h2, h3, h4;
                                if (IsHexChar(_Buffer[_Index + 1], out h1) &&
                                    IsHexChar(_Buffer[_Index + 2], out h2) &&
                                    IsHexChar(_Buffer[_Index + 3], out h3) &&
                                    IsHexChar(_Buffer[_Index + 4], out h4))
                                {
                                    builder.Append((char)(h1 * 0x1000 + h2 * 0x100 + h3 * 0x10 + h4));

                                    _Index += 5;
                                    continue;
                                }
                                else
                                {
                                    throw new JsonFormatterException("无法读取String类型数据", this._Index, new string(this._Buffer));
                                }

                            default:
                                throw new JsonFormatterException("无法读取String类型数据", this._Index, new string(this._Buffer));
                        }

                        ++_Index;
                    }
                }
                else
                {
                    builder.Append(ch);
                }
            }

            return builder.ToString();
        }

        private decimal ParseNumber()
		{
			var start = this._Index;
			while (this._Index < this._Buffer.Length) {
				char ch = this._Buffer [this._Index];
				if ((ch >= '0' && ch <= '9') ||
					(ch == '.') ||
					(ch == '+') ||
					(ch == '-') ||
					(ch == 'e') ||
					(ch == 'E')) {
					this._Index++;
				} else {
					break;
				}
			}

			decimal result;
			if (!decimal.TryParse (new string (_Buffer, start, _Index - start), out result))
				throw new JsonFormatterException ("无法读取Number类型数据", this._Index, new string (this._Buffer));

			return result;
		}

        private Symbols GetToken()
		{
			SkipWhiteSpace ();
			CheckEndOfBuffer ();

			char ch = _Buffer [_Index];
			switch (ch) {
			case '{':
				++_Index;
				return Symbols.BraceLeft;

			case '}':
				++_Index;
				return Symbols.BraceRight;

			case '[':
				++_Index;
				return Symbols.SquareLeft;

			case ']':
				++_Index;
				return Symbols.SquareRight;

			case ':':
				++_Index;
				return Symbols.Colon;

			case ',':
				++_Index;
				return Symbols.Comma;

			case '"':
				++_Index;
				return Symbols.DoubleQuot;

			case 't':
				if (_Index < this._Buffer.Length - 3 &&
					_Buffer [_Index + 1] == 'r' &&
					_Buffer [_Index + 2] == 'u' &&
					_Buffer [_Index + 3] == 'e') {
					_Index += 4;
					return Symbols.True;
				}

				break;

			case 'f':
				if (_Index < this._Buffer.Length - 4 &&
					_Buffer [_Index + 1] == 'a' &&
					_Buffer [_Index + 2] == 'l' &&
					_Buffer [_Index + 3] == 's' &&
					_Buffer [_Index + 4] == 'e') {
					_Index += 5;
					return Symbols.False;
				}

				break;

			case 'n':
				if (_Index < this._Buffer.Length - 3 &&
					_Buffer [_Index + 1] == 'u' &&
					_Buffer [_Index + 2] == 'l' &&
					_Buffer [_Index + 3] == 'l') {
					_Index += 4;
					return Symbols.Null;
				}

				break;

			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
			case '-':
			case '+':
			case '.':
				return Symbols.Number;
			}

			throw new JsonFormatterException ("Json格式错误", this._Index, new string (this._Buffer));
		}

		private void SkipWhiteSpace()
		{
			char ch;
			while (true)
			{
				ch = _Buffer[_Index];
				if (ch > ' ') break;
				if (ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r') break;
				if (++_Index >= _Buffer.Length)
					throw new JsonFormatterException("", this._Index, new string(this._Buffer));
			}
		}

		private void CheckEndOfBuffer()
		{
			if (_Index >= _Buffer.Length)
				throw new JsonFormatterException ("JSON格式错误", _Index, new string (_Buffer)); 
		}

        private static bool IsHexChar(char ch, out uint hex)
        {
            if (ch >= '0' && ch <= '9')
            {
                hex = (uint)(ch - '0');
                return true;
            }

            if (ch >= 'a' && ch <= 'f')
            {
                hex = (uint)(ch - 'a') + 10;
                return true;
            }

            if (ch >= 'A' && ch <= 'F')
            {
                hex = (uint)(ch - 'A') + 10;
                return true;
            }

            hex = 0xFFFFFFFF;
            return false;
        }
    }
}